import { parseHtml } from "./parseHtml";


const defaultTagREG = /\{\{((?:.|\r?\n)+?)\}\}/g

function genPropsStyle(value) { //color:red;background-color: yellow;"
    let obj = {}
    value.split(';').forEach(v => {
        let [key, value] = v.split(':')
        if (key && value) {
            obj[key.trim()] = value.trim()
        }
    })
    return obj
}


function genAttr(attrs) {// 解析属性
    let obj = {}
    attrs.forEach(attr => {
        if (attr.name == 'style') {
            obj[attr.name] = genPropsStyle(attr.value)

        } else {
            obj[attr.name] = attr.value
        }
    });

    return JSON.stringify(obj)
}

function genChild(children) {  // 解析 子元素

    return children.map(item => {
        if (item.type === 1) {  // child为一个组件时
            return genCode(item)
        } else {  // 组件为 文本
            let text = item.text
            let lastIndex = 0
            let match
            let tokens = []
            defaultTagREG.lastIndex = 0
            while (match = defaultTagREG.exec(text)) {
                let index = match.index

                if (index > lastIndex) {

                    tokens.push(`${JSON.stringify(text.slice(lastIndex, match.index))}`)
                }

                tokens.push(`_s(${match[1]})`)

                lastIndex = match[0].length + index
            }
            if (text.length > lastIndex) {

                tokens.push(`${JSON.stringify(text.slice(lastIndex))}`)
            }

            return `_v(${tokens.join('+')})`
        }
    })

}

function genCode(ast) { // 解析ast 语法树为render方法
    let propsStr = genAttr(ast.attrs)
    let children = genChild(ast.children)
    let str = `_c('${ast.tags}',${ast.attrs.length > 0 ? propsStr : null
        }${ast.children.length > 0 ? ',' + children : ''})`
    return str
}


// _c('div', { id: 12,style:'color: 'red'; fontSize: 13 }, children)


export default function compilerToFunction(template) {
    let ast = parseHtml(template)
    const code = genCode(ast)
    const renderFunStr = `with(this){ return ${code}}`
    let render = new Function(renderFunStr)
    return render
}